#include <iostream>
#include <fstream>
#include <vector>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/log/common.hpp>
#include <boost/log/core.hpp>
#include <boost/log/trivial.hpp>
#include <boost/log/sinks.hpp>
#include <boost/log/sources/severity_logger.hpp>
#include <boost/log/sources/record_ostream.hpp>
#include <boost/log/utility/setup.hpp>
#include <boost/log/utility/setup/common_attributes.hpp>
#include <boost/log/attributes.hpp>
#include <boost/log/expressions.hpp>
#include <boost/log/support/date_time.hpp>
#include <boost/format.hpp>
#include <boost/filesystem.hpp>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>

#include "forwarder.h"

using namespace std;
using namespace boost::log;
using namespace boost::property_tree;
using namespace boost::filesystem;

std::vector<shared_ptr<Forwarder>> forwarders;

void makeForwarder(int fromPort, int toPort)
{
    auto forwarder = make_shared<Forwarder>(fromPort, toPort);
    forwarders.push_back(forwarder);
}

void makeForwarder(string& fromIp, int fromPort, string& toIp, int toPort)
{
    auto forwarder = make_shared<Forwarder>(fromIp, fromPort, toIp, toPort);
    forwarders.push_back(forwarder);
}

int main() {
    auto format = expressions::stream
            << expressions::format_date_time<boost::posix_time::ptime>("TimeStamp", "%Y-%m-%d, %H:%M:%S.%f")
            << "[" << expressions::attr<attributes::current_thread_id::value_type>("ThreadID") << "]"
            << "[" << expressions::format_named_scope("Scope", keywords::format = "%n") << "]"
            << "<" << expressions::attr<trivial::severity_level>("Severity") << ">"
            << expressions::message;
    add_file_log(
        keywords::file_name = initial_path().string() + "/sample_%N.log",
        keywords::rotation_size = 10 * 1024 * 1024,
        //keywords::time_based_rotation = sinks::file::rotation_at_time_point(0, 0, 0),
        keywords::auto_flush = true,
        keywords::format = format
    );
    add_console_log(
        std::cout,
        keywords::auto_flush = true,
        keywords::format = format
    );
    core::get()->set_filter(trivial::severity>=trivial::info);
    add_common_attributes();
    core::get()->add_global_attribute("Scope", attributes::named_scope());

    sources::severity_logger<trivial::severity_level> mainLog;
    BOOST_LOG_NAMED_SCOPE("main");
    BOOST_LOG_SEV(mainLog, trivial::info) << "start";

    string configFile = initial_path().string() + "/config.json";
    ptree json;
    read_json(configFile, json);
    for(auto item : json)
    {
        ptree& subJson = item.second;
        string fromIp;
        string toIp;
        if(subJson.find("fromIp") != subJson.not_found())
        {
            fromIp = subJson.get<string>("fromIp");
        }
        int fromPort = subJson.get<int>("fromPort");
        if(subJson.find("toIp") != subJson.not_found())
        {
            fromIp = subJson.get<string>("toIp");
        }
        int toPort = subJson.get<int>("toPort");
        if(fromIp.empty() && toIp.empty())
        {
            makeForwarder(fromPort, toPort);
        }
        else
        {
            makeForwarder(fromIp, fromPort, toIp, toPort);
        }
    }

    while(true)
    {
        char buffer[1024]={0};
        cin.getline(buffer, 1024);
        if(string(buffer)=="exit")
        {
            for(auto forwarder : forwarders)
            {
                forwarder->Stop();
            }
            break;
        }
    }
    BOOST_LOG_SEV(mainLog, trivial::info) << "stop";

    return 0;
}